package wx

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"

	"gitee.com/yanwc/gozero-utils/errx"
	"github.com/zeromicro/go-zero/core/stores/redis"
)

type TemplateMessage struct {
	appId          string
	appSecret      string
	accessTokenKey string
	templateId     string
	redisConf      redis.RedisConf
}

const templateMsgUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=%s"

type Val struct {
	Value string `json:"value"`
	Color string `json:"color,omitempty"`
}

type Data map[string]Val

type TemplateSendResponse struct{}

type body struct {
	Touser           string `json:"touser"`
	TemplateId       string `json:"template_id"`
	Page             string `json:"page"`
	MiniprogramState string `json:"miniprogram_state"`
	Data             Data   `json:"data"`
}

type MiniprogramState string

const WXErrorCode = errx.Code(110002)

const (
	Developer = MiniprogramState("developer")
	Trial     = MiniprogramState("trial")
	Formal    = MiniprogramState("formal")
)

func (msg TemplateMessage) Send(page, openId string, data Data, state MiniprogramState) (err error) {
	accessToken, err := GetAccessToken(msg.appId, msg.appSecret, msg.accessTokenKey, msg.redisConf.NewRedis())
	if err != nil {
		return
	}

	url := fmt.Sprintf(templateMsgUrl, accessToken.AccessToken)
	d := body{
		Touser:           openId,
		TemplateId:       msg.templateId,
		Page:             page,
		MiniprogramState: string(state),
		Data:             data,
	}

	b, err := json.Marshal(d)
	buffer := bytes.NewBuffer(b)
	fmt.Println(string(b))
	if err != nil {
		return
	}

	resp, err := http.Post(url, "application/json;charset:utf-8", buffer)
	if err != nil {
		return
	}

	defer func() {
		_ = resp.Body.Close()
	}()

	if resp.StatusCode != http.StatusOK {
		return errx.New(WXErrorCode, errx.WithMsgOption(resp.Status))
	}

	return
}

func NewTemplateMesage(appId, appSecret, templateId, accessTokenKey string, redisConf redis.RedisConf) TemplateMessage {
	return TemplateMessage{
		appId:          appId,
		appSecret:      appSecret,
		templateId:     templateId,
		accessTokenKey: accessTokenKey,
		redisConf:      redisConf,
	}
}

const uniformMessageTemplateUrl = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=%s"

type UniformMessage struct {
	appId          string
	appSecret      string
	accessTokenKey string
	templateId     string
	redisConf      redis.RedisConf
}

type UniformMessageBody struct {
	ToUser           string           `json:"touser"`
	WeappTemplateMsg WeappTemplateMsg `json:"weapp_template_msg"`
}

type WeappTemplateMsg struct {
	TemplateId string         `json:"template_id"`
	Page       string         `json:"page"`
	FormId     string         `json:"form_id"`
	Data       map[string]Val `json:"data"`
}

func NewUniformMessage(appId, appSecret, templateId, accessTokenKey string, redisConf redis.RedisConf) UniformMessage {
	return UniformMessage{
		appId:          appId,
		appSecret:      appSecret,
		templateId:     templateId,
		accessTokenKey: accessTokenKey,
		redisConf:      redisConf,
	}
}

func (msg UniformMessage) Send(page string, formId string, openId string, data Data) (err error) {
	accessToken, err := GetAccessToken(msg.appId, msg.appSecret, msg.accessTokenKey, msg.redisConf.NewRedis())
	if err != nil {
		return
	}

	url := fmt.Sprintf(uniformMessageTemplateUrl, accessToken.AccessToken)
	d := UniformMessageBody{
		ToUser: openId,
		WeappTemplateMsg: WeappTemplateMsg{
			TemplateId: msg.templateId,
			Page:       page,
			FormId:     formId,
			Data:       data,
		},
	}

	b, err := json.Marshal(d)
	buffer := bytes.NewBuffer(b)
	fmt.Println(string(b))
	if err != nil {
		return
	}

	resp, err := http.Post(url, "application/json;charset:utf-8", buffer)
	if err != nil {
		return
	}

	defer func() {
		_ = resp.Body.Close()
	}()

	if resp.StatusCode != http.StatusOK {
		return errx.New(WXErrorCode, errx.WithMsgOption(resp.Status))
	}

	return
}
